﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using UnityEngine;
using Warensoft.Unity.Communication.Client.Contracts;
using Warensoft.Unity.Communication.Client.Internals;
using Warensoft.Unity.Communication.Client.Models;

namespace Warensoft.Unity.Communication.Client
{
    public class HttpClient
    {
        public static int MaxThreadCount { get; set; }
        protected static HttpClient currentHttpClient;
        protected List<HttpRequest> requests = new List<HttpRequest>();
        protected Queue requestQueue = new Queue();
        protected static HttpConnectionPool connectionPool;
        public event EventHandler<HttpRequestErrorEventArgs> Error;
        public static HttpClient CreateInstance()
        {
            if (currentHttpClient ==null )
            {
                currentHttpClient = new HttpClient();

            }
            return currentHttpClient;
        }
        
        static HttpClient()
        {
            MaxThreadCount = 30;//ThreadManager.MaxThreadCount;
            connectionPool = new HttpConnectionPool(MaxThreadCount);
        }
        protected HttpClient()
        {
            CommunicationManager.SceneUpdate += CommunicationManager_SceneUpdate;
        }

        void CommunicationManager_SceneUpdate(object sender, EventArgs e)
        {
            //所有完成的
            var finishedRequests = this.requests.Where(request => request.Finished).ToList();
            for (int i = 0; i < finishedRequests.Count; i++)
            {
                var request = finishedRequests[i];
               
                this.requests.Remove(request);
                request.Dispose();
                ThreadManager.CurrentThreadCount--;
            }
            //把请的请求加入队列
            while ((ThreadManager .CurrentThreadCount<ThreadManager .MaxThreadCount )&&(this.requestQueue .Count !=0 ))
            {

                var newRequest = this.requestQueue.Dequeue() as HttpRequest;
                newRequest.SendRequestAsync((result) =>
                {
                    if (result .Status!=200)
                    {
                        this.RaiseRequestError(result .Status ,result .StringContent);
                        if (result .Request .ResponseType== HttpResponseTypes.String)
                        {
                            result.Request.StringCallBack(result.StringContent);
                        }
                    }
                    else
                    {
                        switch (result.Request.ResponseType)
                        {

                            case HttpResponseTypes.Bytes:
                                result.Request.BytesCallBack(result.Data);
                                break;
                            case HttpResponseTypes.Image:
                                this.ProcessImageResponse(result);
                                break;
                            case HttpResponseTypes.String:
                                result.Request.StringCallBack(result.StringContent);
                                break;
                            case HttpResponseTypes.XML:
                                XmlDocument doc = new XmlDocument();
                                MemoryStream ms = new MemoryStream(result .Data);
                                doc.Load(ms);
                                ms.Close();
                                result.Request.XMLCallBack(doc);
                                break;
                            case HttpResponseTypes.MovieTexture:
                                this.ProcessMovieTexture(result);
                                break;
                        
                              
                            case HttpResponseTypes.Response:
                                result.Request.ResponseCallback(result);
                                break;
                            default:
                                break;
                        }
                    }
                    
                });
                this.requests.Add(newRequest);
                ThreadManager.CurrentThreadCount++;
            }
        }

        protected virtual void ProcessMovieTexture(HttpResponse result)
        {
            throw new NotImplementedException();
        }


        
        protected virtual void RaiseRequestError(int status, string responseText)
        {
            if (this.Error!=null )
            {
                this.Error(this, new HttpRequestErrorEventArgs()
                { 
                    Status =status,
                    ResponseText =responseText 
                });
            }
        }
        protected virtual void ProcessImageResponse(HttpResponse result)
        {
            throw new NotImplementedException();
        }
       
        public void BeginGetHttpContent(string url, Action<byte[]> callBack)
        {
            

            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                BytesCallBack = callBack,
                ResponseType = HttpResponseTypes.Bytes,
                Method = WebRequestMethods.Get
            });
        }
        
        public void BeginGetHttpContent(string url, Action<string> callBack)
        {

            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                StringCallBack = callBack,
                ResponseType = HttpResponseTypes.String,
                Method = WebRequestMethods.Get
            });
        }
        public void BeginGetHttpContent(string url, Action<XmlDocument> callBack)
        {

            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                XMLCallBack = callBack,
                ResponseType = HttpResponseTypes.XML,
                Method = WebRequestMethods.Get
            });
        }
       
        public void BeginPostHttpContent(string url,byte[]buffer, Action<byte[]> callBack)
        {
            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                BytesCallBack = callBack,
                ResponseType = HttpResponseTypes.Bytes,
                Method = WebRequestMethods.Post,
                Data= buffer
            });
        }
        public void BeginPostHttpContent(string url,byte[]buffer, Action<string> callBack)
        {

            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                StringCallBack = callBack,
                ResponseType = HttpResponseTypes.String                ,
                Method = WebRequestMethods.Post,
                Data=buffer
            });
        }
        public void BeginPostHttpContent(string url,byte[]buffer, Action<XmlDocument> callBack)
        {

            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                XMLCallBack = callBack,
                ResponseType = HttpResponseTypes.XML,
                Method = WebRequestMethods.Post,
                Data=buffer
            });
        }
        public void BeginPost(string url,byte[]buffer,Action<HttpResponse >responseCallback)
        {
            //POST请求长度不能大于3M
            if (buffer.Length > 1024 * 1024 * 3)
            {
                throw new Exception("http post content length cannot longer than 3M");
            }
            this.requestQueue.Enqueue(new HttpRequest()
            {
                Url = url,
                ResponseCallback = responseCallback,
                ResponseType = HttpResponseTypes.Response,
                Method = WebRequestMethods.Post,
                Data= buffer
            });
        }
        
        public void BeginPost(string url,IMessage message, Action<HttpResponse> responseCallback)
        {
            
            this.BeginPost(url,message.ToArray (),responseCallback);
        }
    }
    public class UnityHttpClient:HttpClient
    {
        private UnityHttpClient()
        { }
        protected static UnityHttpClient currentHttpClient;

        public static UnityHttpClient CreateInstance()
        {
            if (currentHttpClient == null)
            {
                currentHttpClient = new UnityHttpClient();

            }
            return currentHttpClient;
        }
        protected override void ProcessImageResponse(HttpResponse result)
        {
            Texture2D image = new Texture2D(100, 100);
            image.LoadImage(result.Data);
            ((UnityHttpRequest)result.Request).ImageCallBack(image);
        }
       
        protected override void ProcessMovieTexture(HttpResponse result)
        {
            var reqeust = result.Request as UnityHttpRequest;
            reqeust.MovieTextureCallback(reqeust.Movie);
        }
        public void BeginGetHttpContent(string url, Action<Texture2D> callBack)
        {

            this.requestQueue.Enqueue(new UnityHttpRequest()
            {
                Url = url,
                ImageCallBack = callBack,
                ResponseType = HttpResponseTypes.Image,
                Method = WebRequestMethods.Get 
            });
        }
        public void BeginGetHttpContent(string url, Action<MovieTexture> callBack)
        {
            this.requestQueue.Enqueue(new UnityHttpRequest(true)
            {
                Url = url,
                MovieTextureCallback = callBack,
                ResponseType = HttpResponseTypes.MovieTexture,
                Method = WebRequestMethods.Get
            });
        }
        public void BeginPostHttpContent(string url,byte[]buffer ,Action<Texture2D> callBack)
        {

            this.requestQueue.Enqueue(new UnityHttpRequest()
            {
                Url = url,
                ImageCallBack = callBack,
                ResponseType = HttpResponseTypes.Image,
                Method = WebRequestMethods.Post,
                Data=buffer
            });
        }
    }
}
